local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local os = os
local string = string
local tonumber = tonumber
local pcall = pcall
local unpack = unpack
local math = math
local conf = require "conf"
local util = require "util"
local pairs = pairs
package.cpath = "/opt/xyitech/jieyan-backend-production/xbit/?.so"
local xbit = require 'xbit'
package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'
module(...)
_VERSION = '0.1'
 _int32_t = 0
 _int16_t = 1
 _float = 2
 _uint32_t = 4
 _uint16_t = 5
 _uint8_t = 6
 _int8_t = 7
 _dynamic = 99
 local _fs = util.getChannel("fs_all")
 local _ws = util.getChannel("ws_all")

function create(user, args)
    local name, alias, aid, spoint_id, model, id, weight,max_weight = args.name, args.alias, args.aid, args.spoint_id, args.model, args.id, args.weight, args.max_weight
    local db = conf.get_mysql()
    local vals = {}
    if id and tonumber(id) then
        vals[#vals + 1] = "id = " .. tonumber(id)
    end

    if alias then
        vals[#vals + 1] = "alias = '" .. alias .. "'"
    end

    if weight then
        vals[#vals + 1] = "weight = " .. weight
    end

    if max_weight then
        vals[#vals + 1] = "max_weight = " .. max_weight
    end

    if args.volt_offset then
        vals[#vals + 1] = "volt_offset = " .. args.volt_offset
    end

    if name then
        vals[#vals + 1] = "name = '" .. name .. "'"
    end

    if model then
        vals[#vals + 1] = "model = '" .. model .. "'"
    end

    if aid then
        vals[#vals + 1] = "aid = " .. aid
    else
        vals[#vals + 1] = "aid = " .. user.aid
    end

    if args.org_id then
        vals[#vals + 1] = "org_id = " .. args.org_id
    else
        vals[#vals + 1] = "org_id = " .. user.org_id
    end

    if spoint_id then
        vals[#vals + 1] = "spoint_id = " .. spoint_id
    end

    vals[#vals + 1] = "create_time = " .. os.time()
    vals[#vals + 1] = "update_time = " .. os.time()
    vals[#vals + 1] = "status = 0"
    
    local res = db:query("INSERT INTO `plane` SET " .. table.concat(vals, ","))
    return res
end

function createController(user, args)
    local res = create(user, args)
    local db = conf.get_mysql()

    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '创建失败'
        }))
        ngx.exit(200)
    else
        local insert_id = res.insert_id
        if insert_id < 1 then
            res = db:query("SELECT LAST_INSERT_ID() AS insert_id")
            if res and res[1] and res[1].insert_id then
                insert_id = res[1].insert_id
            end
        end
        ngx.print(json.encode({
            err = 0,
            id = insert_id,
            msg = '创建成功'
        }))
        ngx.exit(200)
    end
end

function search(user, args)
    local page_no, page_size, option, id, name, spoint_id, aid = tonumber(args.page_no), tonumber(args.page_size), tonumber(args.option), args.id, args.name, args.spoint_id, args.aid
    local db = conf.get_mysql()
    local sql = nil
    local count = nil
    local res = nil
    if option == 1 then
        sql =  "SELECT *,(SELECT name FROM spoint WHERE id = plane.spoint_id) AS 'airport' FROM `plane` WHERE status = 2"
    elseif option == 2 then
        sql = "SELECT `plane`.create_time, `plane`.id, `plane`.aid, (SELECT name from area where id = `plane`.aid) as area,`plane`.volt_offset, `plane`.model,`plane`.weight, `plane`.name, (SELECT name FROM spoint WHERE id = plane.spoint_id) AS 'airport',(SELECT lat FROM spoint WHERE id = plane.spoint_id) AS 'elat',(SELECT lng FROM spoint WHERE id = plane.spoint_id) AS 'elng', `order`.id AS 'orderId', `order`.serial_no, `order`.route, (SELECT name from route where id = `order`.route) as routeName, `order`.state, `order`.t2, `order`.t4, `order`.t5 FROM `plane` left join `order` on `plane`.id = `order`.fid WHERE `plane`.status = 1"
        if args.state and tonumber(args.state) then
            sql = sql .. " AND `order`.state = " .. tonumber(args.state)
        else
            sql = sql .. " AND `order`.state = 2"
        end
        if args.serial_no then
            sql = sql .. " AND `order`.serial_no = '" .. args.serial_no .. "'"
        end
    elseif option == 3 then
        sql = "SELECT *,(SELECT name FROM `spoint` WHERE id = plane.spoint_id) AS 'airport',(SELECT serial_no FROM `order` WHERE fid = plane.id ORDER BY `order`.t0 DESC LIMIT 1) AS 'serial_no',(SELECT `route`.name FROM `order` left join `route` on `order`.route = `route`.id WHERE fid = plane.id  ORDER BY `order`.t0 DESC LIMIT 1) AS 'route' FROM `plane` WHERE 1 = 1"
        if args.status and tonumber(args.status) then
            sql = sql .. " AND `plane`.status = " .. tonumber(args.status)
        end

        if args.spoint_id and tonumber(args.spoint_id) then
            sql = sql .. " AND `plane`.spoint_id= " .. tonumber(args.spoint_id)
        end
    else
        sql = "SELECT * FROM `plane` WHERE 1=1"
    end

    if name then
        sql = sql ..  " AND `plane`.name like '%" .. name .. "%'"
    end

    if alias then
        sql = sql ..  " AND `plane`.alias like '%" .. alias .. "%'"
    end

    if id then
        sql = sql ..  " AND `plane`.id = " .. id
    end

    if aid then
        local ids = conf.get_aids(tonumber(aid))
        sql = sql .. " AND `plane`.aid in (" ..  table.concat(ids, ",") .. ")"
    end

    if args.org_id then
        local ids = conf.get_orgIds(nil, tonumber(args.org_id))
        sql = sql .. " AND `plane`.org_id in (" ..  table.concat(ids, ",") .. ")"
    end
    
    sql = sql .. " AND `plane`.aid in (" ..  table.concat(user.aids, ",") .. ")"

    sql = sql .. " AND `plane`.org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    local count = #(db:query(sql) or {})

    sql = sql .. " ORDER BY field(`plane`.status,1,0,2)"

    if page_no and page_size then
        sql = sql .. " LIMIT " .. (page_no * page_size) .. "," .. page_size
    end

    
    ngx.log(ngx.ERR, sql)
    res = db:query(sql)
    return res, count
end

function searchController(user, args)
    local res, count = search(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = {}
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res,
            count = count
        }))
        ngx.exit(200)
    end
end

function update(user, args)
    local id, status, remark, remark_detail, contact, repair_time, aid, name, alias, model,weight,max_weight = args.id, args.status, args.remark, args.remark_detail, args.contact, args.repair_time, args.aid, args.name, args.alias, args.model, args.weight, args.max_weight
    local blade_renew_at, engine_renew_at = args.blade_renew_at, args.engine_renew_at
    local db = conf.get_mysql()
    local vals = {}
    if aid then
        aid = tonumber(aid)
    end
    local res = db:query("SELECT aid from plane WHERE id = " .. id)
    -- ngx.log(ngx.ERR, util.contains(aids, res[1]["aid"]))
    -- ngx.log(ngx.ERR, aid ~= res[1].aid)
    if not res or not res[1] or not util.contains(user.aids, res[1]["aid"]) then
        ngx.print(json.encode({
            err = 1,
            msg = '权限不足'
        }))
        ngx.exit(200)
    end

    if status and tonumber(status) then
        vals[#vals + 1] = "status = " .. tonumber(status)
    end
    
    if alias then
        vals[#vals + 1] = "alias = '" .. alias .. "'"
    end

    if name then
        vals[#vals + 1] = "name = '" .. name .. "'"
    end

    if remark then
        vals[#vals + 1] = "remark = '" .. remark .."'"
        vals[#vals + 1] = "remark_time = " .. os.time()
    end

    if blade_renew_at then
        vals[#vals + 1] = "blade_renew_at = " .. blade_renew_at
    end

    if engine_renew_at then
        vals[#vals + 1] = "engine_renew_at = " .. engine_renew_at
    end
    
    if aid then
        vals[#vals + 1] = "aid = " .. aid
    end

    if args.battery_id then
        vals[#vals + 1] = "battery_id = " .. args.battery_id
    end

    if args.org_id then
        vals[#vals + 1] = "org_id = " .. args.org_id
    end

    if model then
        vals[#vals + 1] = "model = '" .. model .. "'"
    end

    if remark_detail then
        vals[#vals + 1] = "remark_detail = '" .. remark_detail .."'"
        vals[#vals + 1] = "remark_time = " .. os.time()
    end
    
    if weight then
        vals[#vals + 1] = "weight = " .. weight
    end

    if args.volt_offset then
        vals[#vals + 1] = "volt_offset = " .. args.volt_offset
    end

    if max_weight then
        vals[#vals + 1] = "max_weight = " .. max_weight
    end

    if contact then
        vals[#vals + 1] = "contact = '" .. contact .."'"
    end
    
    if repair_time then
        vals[#vals + 1] = "repair_time = unix_timestamp('" .. repair_time .. "')"
    end

    vals[#vals + 1] = "update_time = " .. os.time()

    local sql = "UPDATE `plane` SET " .. table.concat(vals, ",") .. " WHERE id = " .. id
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)--AND aid = " .. aid
    return res
end

function updateController(user, args)
    local res = update(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '更新失败'
        }))
        ngx.exit(200)
    else 
        ngx.print(json.encode({
            err = 0,
            msg = '更新成功'
        }))
        ngx.exit(200)
    end
end

function listPlaneIdsController(user, args)
    local res = listPlaneIds(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = {}
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = ids
        }))
        ngx.exit(200)
    end
end

function listPlaneIds(user, args)
    local db = conf.get_mysql()
    local ids = {}
    local sql = "SELECT id FROM plane WHERE 1=1"
    sql = sql .. " AND org_id in (" ..  table.concat(user.orgIds, ",") .. ")"
    sql = sql .. " AND aid in (" ..  table.concat(user.aids, ",") .. ")"
    local res = db:query(sql)    
    if res then
        for k,v in pairs(res) do
            table.insert(ids, tonumber(v.id))
        end
    end
    return ids
end

function listPlaneName(user, args)
    local db = conf.get_mysql()
    local sql = "SELECT DISTINCT id, name FROM plane WHERE 1=1"
    sql = sql .. " AND org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    local res = db:query(sql)    
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = {}
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function delete(user, args)
    local db = conf.get_mysql()

    local res = db:query("DELETE FROM `plane` WHERE id = " .. args.id )
    return res
end

function deleteController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 2,
            msg = '缺少id'
        }))
    end
    local res = delete(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '更新失败'
        }))
        ngx.exit(200)
    else 
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function args2bit(args, red_p)
    ngx.log(ngx.ERR, json.encode(args))
    local data = xbit.tobit2(unpack(args))
    ngx.log(ngx.ERR, xbit.tohex(data))
    local prefix = xbit.tobit2(unpack({_uint32_t, #data}))
    ngx.log(ngx.ERR, prefix)
    local final = prefix .. data
    local res, err = red_p:publish(_fs, final)
    ngx.log(ngx.ERR, res)
    if err then
        ngx.log(ngx.ERR, err)
        ngx.print(json.encode({
            err = 7,
            msg = 'redis错误'
        }))
        ngx.exit(200)
    end
    return final
end


function autoTakeOff(user, args)
    local redis = require "redis"
    local db = conf.get_mysql()
    local red = redis:new()
    local ok, err = red:connect("127.0.0.1", 6379)
    local res, err = red:subscribe(_ws)
    local red_p = redis:new()
    local ok, err = red_p:connect("127.0.0.1", 6379)
    local red_set = conf.get_redis()
    local protocal = require 'protocal'
    local order,fid
    local i = 1
    local sql = "SELECT * FROM `order` WHERE id = " .. args.id
    local res = db:query(sql)

    if not args.id then
        ngx.print(json.encode({
            err = 1,
            msg = '参数不对'
        }))
        ngx.exit(200)
    end
    if not res or #res == 0 then
        ngx.print(json.encode({
            err = 2,
            msg = '订单未找到'
        }))
        ngx.exit(200)
    end
    order = res[1]
    
    red_set:set("weight_" .. order.fid, tonumber(order.weight))

    fid = tonumber(order.fid)
    if not fid then
        ngx.print(json.encode({
            err = 3,
            msg = '飞机信息有误'
        }))
        ngx.exit(200)
    end

    if not order.route then
        ngx.print(json.encode({
            err = 4,
            msg = '航路未找到'
        }))
        ngx.exit(200)
    end

    sql = "SELECT * FROM `route` WHERE id = " .. order.route
    local route = db:query(sql)
    if not route or #route == 0 then
        ngx.print(json.encode({
            err = 4,
            msg = '航路未找到'
        }))
        ngx.exit(200)
    end

    order.route_id = order.route
    order.route = route[1]
    order.serial_no = args.serial_no or ""
    order.detail = json.decode(route[1].detail)
    ngx.log(ngx.ERR, json.encode(order.detail))
    local heightDiff = order.height_diff or 0
    local routeBuffer = nil
    local indexes = {101, 102, 105, 106, 107, 108, 101, 102}
    local count = 0
    local maxcount = 150
    local res = nil
    local filterData = function(fid, data, i)
        local msgId = xbit.readBuff(_uint8_t, data, 0)
        local _fid = xbit.readBuff(_uint32_t, data, 1)
        ngx.log(ngx.ERR, fid, ":",_fid, ".", msgId, ":", indexes[i])
        -- ngx.log(ngx.ERR, fid == _fid)
        -- ngx.log(ngx.ERR, msgId == indexes[i])
        if fid == _fid then
            count = count + 1

            if count > maxcount then
                return {
                    err = 9,
                    msg = '超过时间无应答'
                }, i
            end
            if msgId == indexes[i] then
                if i == 2 then
                    count = 0
                    local command = xbit.readBuff(_uint16_t, data, 5)
                    local response = xbit.readBuff(_uint8_t, data, 7)
                    ngx.log(ngx.ERR, command)
                    ngx.log(ngx.ERR, response)
                    if command == 9 then
                        if response == 0 then
                            i = i + 1
                            return nil, i
                        else
                            return {
                                err = 5,
                                msg = '高度差设置错误'
                            }, i
                        end
                    end
                elseif i == 4 then
                    count = 0
                    local response = xbit.readBuff(_uint8_t, data, 6)
                    local errorCodes = {["1"] = "任务加载错误", ["2"] = "坐标系不支持", ["3"] = "指令不支持", ["4"] = "航路点越界", ["5"] = "非法参数1", ["11"] = "非法参数2", ["7"] = "任务拒绝",
                        ["8"] = "带参数应答", ["9"] = "航路起点位置偏离", ["10"] = "航路距离超程", ["11"] = "设备未就绪", ["12"] = "GPS信号不佳", ["13"] = "正在更新固件"
                    }
                    local msg =  errorCodes[response..""] or ""
                    -- ngx.log(ngx.ERR, command)
                    -- ngx.log(ngx.ERR, response)
                    if response == 0 then
                        i = i + 1
                        return nil, i
                    else
                        return {
                            err = response,
                            msg = msg
                        }, i
                    end
                elseif i == 6 then
                    count = 0
                    -- ngx.log(ngx.ERR, xbit.tohex(routeBuffer))
                    -- ngx.log(ngx.ERR, xbit.tohex(data))
                    -- ngx.log(ngx.ERR, string.sub(routeBuffer, 18))
                    -- ngx.log(ngx.ERR, string.sub(data, 11, #data - 4))
                    -- ngx.log(ngx.ERR, string.sub(routeBuffer, 18) == string.sub(data, 11, #data - 4))
                    if string.sub(routeBuffer, 18) == string.sub(data, 11, #data - 4) then
                        i = i + 1
                        return nil, i
                    else
                        return {
                            err = 7,
                            msg = "航路信息确认错误"
                        }, i
                    end
                elseif i == 8 then
                    count = 0
                    ngx.log(ngx.ERR, xbit.tohex(data))
                    local command = xbit.readBuff(_uint16_t, data, 5)
                    local response = xbit.readBuff(_uint8_t, data, 7)
                    if command == 11 then
                        if response == 0 then
                            local now = os.time()
                            red_p:publish(_ws, json.encode({246, fid, now}))
                            red_set:set("takeoff_" .. fid, os.time())
                            red_set:set("order_" .. fid, json.encode(order))
                            args2bit({_uint8_t, 110, _uint32_t, fid}, red_p)
                            return {
                                err = 0,
                                msg = '自动起飞成功'
                            }, i
                            -- ngx.exit(200)
                        else
                            local errorCodes = {["1"] = "临时拒绝", ["2"] = "永久拒绝", ["3"] = "不支持", ["4"] = "执行失败", ["10"] = "非自主失败", ["11"] = "未解锁失败", ["12"] = "飞控未就绪，请10秒后重试"}
                            local err =  errorCodes[response..""] or ""
                            return {
                                err = response,
                                msg = '起飞失败：' .. err
                            }, i
                        end
                    end
                else
                    if i == 8 then
                        local now = os.time()
                        red_p:publish(_ws, json.encode({246, fid, now}))
                        red_set:set("takeoff_" .. fid, os.time())
                        red_set:set("order_" .. fid, json.encode(order))
                        red_set:expire("order_" .. fid, 6000)
                        return {
                            err = 0,
                            msg = '自动起飞成功'
                        }, i
                    end
                end
            end
        end
        return nil,i
    end

    local processData = function(fid, i)
        -- ngx.log(ngx.ERR, i)
        if i == 1 then
            local heightDiff = order.height_diff or 0
            local throttle = args.throttle or 0 --0
            ngx.log(ngx.ERR, throttle)
            local args = {_uint8_t, 101, _uint32_t, fid, _uint32_t, os.time().. math.random(0,9), _uint8_t, 0, _uint16_t, 9, _uint8_t, 0, _int32_t, heightDiff * 1000,  _int32_t, throttle * 100, _int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0}
            args2bit(args, red_p)
            i = i + 1
        elseif i == 3 then
            local args = {_uint8_t, 105, _uint32_t, fid, _uint32_t, os.time().. math.random(0,9), _uint8_t, 0, _uint16_t, #order.detail, _uint8_t, 2}
            for i = 1, #order.detail do
                local point = order.detail[i]
                args[#args + 1] = _int32_t
                args[#args + 1] = point.lat * 1e7
                args[#args + 1] = _int32_t
                args[#args + 1] = point.lng * 1e7
                args[#args + 1] = _int32_t
                args[#args + 1] = point.alt * 1e3
                args[#args + 1] = _int32_t
                args[#args + 1] = point.v * 1e3
            end
            ngx.log(ngx.ERR, json.encode(args))
            routeBuffer = args2bit(args, red_p)
            i = i + 1
        elseif i == 5 then
            local args = {_uint8_t, 107, _uint32_t, fid, _uint32_t, os.time().. math.random(0,9), _uint8_t, 0, _uint8_t, 2}
            args2bit(args, red_p)
            i = i + 1
        elseif i == 7 then
            local args = {_uint8_t, 101, _uint32_t, fid, _uint32_t, os.time().. math.random(0,9),  _uint8_t, 0, _uint16_t, 11, _uint8_t, 0,_uint32_t, fid,  _int32_t, 0, _int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0}
            args2bit(args, red_p)
            i = i + 1
        end
        return i
    end
    local fromTcp = function()
        while true do
            local res, err = red:read_reply()
            if res then
                local data = res[3]
                -- -- TODO transfer buffer data to json
                -- ngx.log(ngx.ERR, "data is ", data)
                res, i = filterData(fid, data, i)
                -- ngx.log(ngx.ERR, ok)
                i = processData(fid, i)

                if i > #indexes or res then
                    ngx.log(ngx.ERR, json.encode(res))
                    return res
                end
            else
                if err ~= "timeout" then
                    -- red:close()
                    ngx.log(ngx.ERR, "Redis read error: ", err)
                    return ngx.exit(444)
                end
            end
        end
    end
    ngx.log(ngx.ERR, "processData")
    
    i = processData(fid, i)
    local co = ngx.thread.spawn(fromTcp)
    local ok, _res = ngx.thread.wait(co)
    return _res
end

function checkPlaneBatteryStatus(route, height_diff, volt, planeWeight, packageWeight, model)
    if model == "TR5" then

    elseif model == "N6" then
        return false, 0.2
        -- volt = volt * 2
    else
        return false, 0.2
    end
    local remain = util.remainBatteryTimeBeforeFlight(volt, planeWeight, packageWeight)
    local flightTimeDetail = util.flightTimeDetail(route, height_diff)
    -- ngx.log(ngx.ERR, remain)
    -- ngx.log(ngx.ERR, flightTime)
    local estimateBatteryAfterFlight = util.estimateBatteryAfterFlight(planeWeight + packageWeight, flightTimeDetail, util.remainBatteryPercent(volt, false))
    ngx.log(ngx.ERR, estimateBatteryAfterFlight)
    return tonumber(remain) - tonumber(flightTimeDetail.total.t) < 300, estimateBatteryAfterFlight
    -- return false, 0.2
end

function updatePlaneDetails()
    local db = conf.get_mysql()
    local fids = db:query("SELECT id,detail_update_time,total_flight_count,total_flight_seconds,total_flight_m FROM plane")
    for k,v in pairs(fids) do
        local vals = {}
        local orders, err = db:query("SELECT `order`.id, `order`.route, `route`.distance, `route`.duration FROM `order` left join `route` on `route`.id = `order`.route WHERE `order`.fid = " .. v.id .. " AND (`order`.state = 4 OR `order`.state = 5) AND `order`.t0 > " .. v.detail_update_time)
        ngx.log(ngx.ERR, err)
        local total_flight_count = tonumber(v.total_flight_count) + #orders
        local total_flight_m = v.total_flight_m + util.reduce(orders, function(mem, n) return mem + tonumber(n.distance) end, 0)
        local total_flight_seconds = v.total_flight_seconds + util.reduce(orders, function(mem, n) return mem + tonumber(n.duration) end, 0)
        vals[#vals + 1] = "detail_update_time = " .. os.time()
        vals[#vals + 1] = "total_flight_count = " .. total_flight_count
        vals[#vals + 1] = "total_flight_m = " .. total_flight_m
        vals[#vals + 1] = "total_flight_seconds = " .. total_flight_seconds

        db:query("UPDATE `plane` SET " .. table.concat(vals, ",") .. " WHERE id = " .. v.id)
    end
    ngx.print(json.encode({
        err = 0,
        msg = 'ok'
    }))
    ngx.exit(200)
end

function getWeightByFid(fid)
    if not ngx.fid_weight then
        ngx.fid_weight = {}
        local conf = require "conf"
        local db = conf.get_mysql()
        local res, err = db:query("SELECT id, weight from plane")
        if res then
            for k,v in pairs(res) do
                ngx.fid_weight[v.id .. ""] = v.weight
            end 
        end 
    end
    if fid then
        return ngx.fid_weight[fid .. ""]
    else
        return ngx.fid_weight
    end
end

function getPlanesBySpoint()
    local db = conf.get_mysql()
    local spoints = {}
    local planes = db:query("SELECT name,spoint_id FROM `plane`")
    if planes then
        for k,v in pairs(planes) do 
            if not spoints[v.spoint_id .. ""] then
                spoints[v.spoint_id .. ""] = {}
            else
                table.insert(spoints[v.spoint_id .. ""], v.name)
            end
        end
    end
    return spoints
end

function getModel(user, args)
    local db = conf.get_mysql()
    local sql = "SELECT * FROM `plane_model` WHERE 1=1"
    if args.id then
        sql = sql .. " AND id = " .. args.id
    end

    if args.model then
        sql = sql .. " AND model = '" .. args.model .. "'"
    end

    local res = db:query(sql)
    return res
end

function getModelController(user, args)
    local res = getModel(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '数据有误'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function getMonitorInfo(user, args)
    local red = conf.get_redis()
    local route = require 'route'
    local fid = args.fid
    local res = {}
    local _route = nil
    -- local volt = red:get("voltage_"..fid)
    local order = red:get("order_"..fid)
    if order and order ~= ngx.null then
        order = json.decode(order)
        _route = route.search(user, {["id"] = order.routeId})
    end
    
    local actualWeight = red:get("actualWeight_"..fid)
    local batteryAfterFlight = red:get("batteryAfterFlight_"..fid)
    if batteryAfterFlight and batteryAfterFlight ~= ngx.null then
        batteryAfterFlight = string.format("%0.1f", batteryAfterFlight * 100)..'%'
    end
    res.order = order
    if _route then
        res.routeName = _route[1].name
    end
    res.actualWeight = actualWeight
    res.batteryAfterFlight = batteryAfterFlight
    return res
end

function getMonitorInfoController(user, args)
    if not args.fid then
        ngx.print(json.encode({
            err = 1,
            msg = '参数不对'
        }))
        ngx.exit(200)
    end

    local res = getMonitorInfo(user, args)
    ngx.print(json.encode({
        err = 0,
        msg = res
    }))
    ngx.exit(200)
end

function load(user, args)
    local redis = require "redis"
    local fid = args.fid
    local args = {_uint8_t, 101, _uint32_t, fid, _uint32_t, os.time().. math.random(0,9),  _uint8_t, 0, _uint16_t, 16, _uint8_t, 0,_int32_t, args.option,  _int32_t, 0, _int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0,_int32_t, 0}
    local red_p = redis:new()
    local ok, err = red_p:connect("127.0.0.1", 6379)
    args2bit(args, red_p)
end

function loadController(user, args)
    if not args.fid or not args.option then
        ngx.print(json.encode({
            err = 1,
            msg = "缺少参数"
        }))
        ngx.exit(200)
    end
    load(user, args)
    ngx.print(json.encode({
        err = 0,
        msg = "发送成功"
    }))
    ngx.exit(200)
end

function default(args)    
    if args.action == 'search' then
        local user = conf.parse_token(args, "plane")
        searchController(user, args)
    elseif args.action == 'create' then
        local user = conf.parse_token(args, "plane")
        createController(user, args)
    elseif args.action == 'update' then
        local user = conf.parse_token(args, "plane")
        updateController(user, args)
    elseif args.action == 'delete' then
        local user = conf.parse_token(args, "plane")
        deleteController(user, args)
    elseif args.action == 'listPlaneName' then
        local user = conf.parse_token(args, "plane")
        listPlaneName(user, args)
    elseif args.action == 'autoTakeOff' then
        local user = conf.parse_token(args, "plane")
        autoTakeOff(user, args)
    elseif args.action == 'updatePlaneDetails' then
        updatePlaneDetails()
    elseif args.action == 'getModel' then
        local user = conf.parse_token(args, "plane")
        getModelController(user, args)
    elseif args.action == 'monitorInfo' then
        local user = conf.parse_token(args, "plane")
        getMonitorInfoController(user, args)
    elseif args.action == 'listPlaneIds' then
        local user = conf.parse_token(args, "plane")
        listPlaneIdsController(user, args)
    elseif args.action == 'load' then
        local user = conf.parse_token(args, "plane")
        loadController(user, args)
    end
end

local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)
